#pragma once
#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>
#include <functional>
#include "socket.hpp"
// 简易版计算器
class Request
{
public:
    Request() {}
    Request(int x, int y, char oper) : _x(x), _y(y), _oper(oper)
    {
    }
    std::string Sequence()
    {
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;
        // // 1. FastWriter
        // Json::FastWriter fwriter;
        // std::string s = fwriter.write(root);
        // return s;

        // 2. StreamWriter
        Json::StreamWriterBuilder swb;
        std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
        std::stringstream ss;
        sw->write(root, &ss);
        return ss.str();
    }
    void RSequence(const std::string &seq)
    {
        // 反序列化
        Json::Value root;
        Json::Reader reader;
        if (!reader.parse(seq, root))
        {
            LOG(Level::WARNING) << "parse seq error";
            exit(1);
        }
        _x = root["x"].asInt();
        _y = root["y"].asInt();
        _oper = root["oper"].asInt();
    }
    int Getx() { return _x; }
    int Gety() { return _y; }
    char GetOper() { return _oper; }

private:
    int _x;
    int _y;
    char _oper; // 运算符 + - * / %
};

class Responce
{
public:
    Responce() {}
    Responce(int result, int code) : _result(result), _code(code)
    {
    }
    std::string Sequence()
    {
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;
        Json::StreamWriterBuilder swb;
        std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
        std::stringstream ss;
        sw->write(root, &ss);
        return ss.str();
    }
    void RSequence(const std::string &seq)
    {
        Json::Value root;
        Json::Reader reader;
        reader.parse(seq, root);
        _result = root["result"].asInt();
        _code = root["code"].asInt();
    }
    void SetResult(int result) { _result = result; }
    void SetCode(int code) { _code = code; }
    void Show()
    {
        std::cout << "运算结果 : " << _result << "[" << _code << "]" << std::endl;
    }

private:
    int _result; // 结果
    int _code;   // 0 正确、 1/2/3/4... 错误
};

using func_t = std::function<Responce(Request &)>;

static std::string sep = "\r\n";
class Protocol
{
public:
    Protocol() {}
    Protocol(func_t func) : _func(func) {}
    ~Protocol() {}
    // 增加报头
    // 30\r\n{age:19,love:study,name:lxb}\r\n
    std::string Encode(const std::string &massage)
    {
        int sz = massage.size();
        std::string str = std::to_string(sz) + sep + massage + sep;
        return str;
    }
    // 读取数据存在完整报文就取出来，不存在就继续读
    bool Decode(std::string &buff, std::string *packet)
    {
        // 判断是否存在sep
        auto pos = buff.find(sep);
        if (pos == std::string::npos)
            return false;
        // 是否存在完整报文
        int head_len = std::stoi(buff.substr(0, pos));
        int len = pos + head_len + sep.size() + 2;
        if (buff.size() < len)
            return false;
        // 存在一个完整的报文，取出
        // *packet = buff.substr(0, len);
        *packet = buff.substr(pos + sep.size(), head_len);
        // 在buff中删除该报文
        buff.erase(0, len);
        return true;
    }
    void GetRequest(std::shared_ptr<Socket> sock, InetAddr &addr)
    {
        while (true)
        {
            // 读取？
            // Socket提供
            std::string buff;
            while (true)
            {
                int n = sock->Recv(buff);
                if (n < 0)
                {
                    LOG(Level::WARNING) << "recv error";
                    exit(1);
                }
                else if (n == 0)
                {
                    LOG(Level::DEBUG) << "client exit";
                    exit(OK);
                }
                std::cout << "-----------------------recv buff--------------" << std::endl
                          << buff << "-----------------------------" << std::endl;
                // 1. 判断报文完整性
                std::string packet;
                while (Decode(buff, &packet))
                {
                    // 2. 反序列化
                    Request req;
                    req.RSequence(packet);
                    std::cout << "-----------------------packet--------------" << std::endl
                              << packet << "\n---------------------------------" << std::endl;
                    //..Cal 上层提供
                    Responce res = _func(req);
                    // 4. 将结果序列化
                    std::string json_res = res.Sequence();
                    std::cout << "-----------------------json_res--------------" << std::endl
                              << json_res << "\n-----------------------------" << std::endl;
                    // 5.加协议报头
                    std::string send_res = Encode(json_res);
                    std::cout << "-----------------------send_res--------------" << std::endl
                              << send_res << "\n-----------------------------" << std::endl;
                    // 6. 发送
                    int sn = sock->Send(send_res);
                    if (sn < 0)
                    {
                        LOG(Level::DEBUG) << "send error";
                        exit(2);
                    }
                }
            }
        }
    }
    std::string BuildComData(int x, int y, char oper)
    {
        // 结构化
        Request req(x, y, oper);
        // 序列化
        std::string json_req = req.Sequence();
        // 添加协议报头
        return Encode(json_req);
    }
    bool GetResponce(std::shared_ptr<TcpSocket> &sock, std::string &buffer, Responce *res)
    {
        int n = sock->Recv(buffer);
        if (n > 0)
        {
            std::string answer;
            if (Decode(buffer, &answer))
            {
                // 读取到一个完整应答报文
                // 反序列化
                std::cout << "**********buffer**********" << std::endl
                          << buffer << "**************************" << std::endl;
                res->RSequence(answer);
                std::cout << "**********answer**********" << std::endl
                          << answer << "**************************" << std::endl;
                return true;
            }
        }
        else if (n == 0)
        {
            LOG(Level::DEBUG) << "server exit";
            exit(OK);
        }
        else
        {
            LOG(Level::WARNING) << "recv error";
            exit(1);
        }
        return false;
    }

private:
    func_t _func;
};